﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Mathematics.cs" company="">
//   
// </copyright>
// <summary>
//   The mathematics.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace FrontalMethod
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Drawing2D;

    /// <summary>
    /// The mathematics.
    /// </summary>
    internal class Mathematics
    {
        /// <summary>
        /// Нахождение расстояния между двумя точками
        /// </summary>
        /// <param name="p1">
        /// Точка 1
        /// </param>
        /// <param name="p2">
        /// Точка 2
        /// </param>
        /// <returns>
        /// расстояние между точками
        /// </returns>
        public double FindDist(Point p1, Point p2)
        {
            double Dist = Math.Sqrt(((p1.X - p2.X) * (p1.X - p2.X)) + ((p1.Y - p2.Y) * (p1.Y - p2.Y)));
            return Dist;
        }

        /// <summary>
        /// Закон косинуса для нахождения угла треугольника
        /// </summary>
        /// <param name="a">
        /// сторона напротив угла
        /// </param>
        /// <param name="b">
        /// сторона 2
        /// </param>
        /// <param name="c">
        /// сторона 3
        /// </param>
        /// <returns>
        /// угол треугольника, град
        /// </returns>
        public double CosineLaw(double a, double b, double c)
        {
            double angle = Math.Acos((b * b + c * c - a * a) / (2 * b * c));
            angle = angle * 180 / Math.PI;
            return angle;
        }

        /// <summary>
        /// Закон косинуса для нахождения одной из сторон треугольника
        /// </summary>
        /// <param name="angle">
        /// угол напротив искомой стороны
        /// </param>
        /// <param name="b">
        /// сторона 1
        /// </param>
        /// <param name="c">
        /// сторона 2
        /// </param>
        /// <returns>
        /// искомая сторона
        /// </returns>
        public double CosineLaw2(double angle, double b, double c)
        {
            angle = (angle * Math.PI) / 180;
            double a = Math.Sqrt(b * b + c * c - 2 * b * c * Math.Cos(angle));
            return a;
        }

        /// <summary>
        /// Нахождение шага разбиения стороны
        /// </summary>
        /// <param name="fSide">
        /// длина стороны
        /// </param>
        /// <param name="step">
        /// первоначальный шаг разбиения
        /// </param>
        /// <returns>
        /// новый шаг разбиения
        /// </returns>
        public double FindNewStep(double fSide, double step)
        {
            double newStep = 0;
            double n, step1, step2;
            n = fSide / step;
            if (n <= 1.4f)
            {
                newStep = fSide;
            }
            else if (fSide % step <= 0.3f * step)
            {
                newStep = step;
            }
            else
            {
                step1 = step;
                step2 = step;
                while ((fSide % step) > (0.3f * step))
                {
                    step1 = step1 + 0.1f;
                    if ((fSide % step1) <= (0.3f * step1))
                    {
                        return step1;
                    }

                    step2 = step2 - 0.1f;
                    if ((fSide % step2) <= (0.3f * step2))
                    {
                        return step2;
                    }
                }
            }

            return newStep;
        }

        /// <summary>
        /// Нахождение расстояния от точки до прямой, заданной двумя точками
        /// </summary>
        /// <param name="p">
        /// точка
        /// </param>
        /// <param name="lp1">
        /// точка прямой 1
        /// </param>
        /// <param name="lp2">
        /// точка прямой 2
        /// </param>
        /// <returns>
        /// расстояние от точки до прямой
        /// </returns>
        public double FindDistPoint2Line(Point p, Point lp1, Point lp2)
        {
            if (lp1.X == lp2.X)
            {
                return Math.Abs(p.X - lp1.X);
            }

            double fDist = 0;
            double k, b;
            k = 1.0 * (lp2.Y - lp1.Y) / (1.0 * (lp2.X - lp1.X));
            b = lp2.Y - k * lp2.X;
            fDist = Math.Abs(p.Y - k * p.X - b) / Math.Sqrt(k * k + 1);
            return fDist;
        }

        /// <summary>
        /// Проверка условия расположения точки напротив прямой
        /// </summary>
        /// <param name="d1">
        /// расстояние от первой точки прямой до точки
        /// </param>
        /// <param name="d2">
        /// расстояние от второй точки прямой до точки
        /// </param>
        /// <param name="h">
        /// расстояние от точки до прямой
        /// </param>
        /// <param name="Len">
        /// расстояние между точками прямой
        /// </param>
        /// <returns>
        /// признак расположения точки напротив прямой
        /// </returns>
        public bool NearPoint(double d1, double d2, double h, double Len)
        {
            bool bIsNear = false;
            double l1, l2;
            l1 = Math.Sqrt(d1 * d1 - h * h);
            l2 = Math.Sqrt(d2 * d2 - h * h);
            if ((l1 + l2 <= Len + 0.0001f) && (l1 + l2 >= Len - 0.0001f))
            {
                bIsNear = true;
            }

            return bIsNear;
        }

        /// <summary>
        /// Нахождение координит нового узла, находящегося внутри некоторой области
        /// </summary>
        /// <param name="p1">
        /// координаты первой точки, от которой строится новый узел
        /// </param>
        /// <param name="p2">
        /// координаты второй точки, от которой строится новый узел
        /// </param>
        /// <param name="l1">
        /// расстояние от первой точки до нового узла
        /// </param>
        /// <param name="l2">
        /// расстояние от второй точки до нового узла
        /// </param>
        /// <param name="gp">
        /// область, ограничивающая возможные варианты построения нового узла
        /// </param>
        /// <param name="p_l">
        /// функция возвращает 2 точки, если обе они принадлежат заданной области (левая точка)
        /// </param>
        /// <param name="p_r">
        /// функция возвращает 2 точки, если обе они принадлежат заданной области (правая точка)
        /// </param>
        public void FindPoint(Point p1, Point p2, double l1, double l2, GraphicsPath gp, ref Point p_l, ref Point p_r)
        {
            var p = new Point();
            p_l = new Point(-1000, -1000);
            p_r = new Point(-1000, -1000);

            double a, b, c, D, x1, x2, y1, y2, A_;
            double deltaX = 1.0 * (p2.X - p1.X);
            double deltaY = 1.0 * (p2.Y - p1.Y);
            A_ = 1.0 *
                 (1.0 * (l1 * l1) - 1.0 * (p1.X * p1.X) - 1.0 * (l2 * l2) - 1.0 * (p1.Y * p1.Y) + 1.0 * (p2.X * p2.X) +
                  1.0 * (p2.Y * p2.Y));
            a = 4.0 * deltaX * deltaX + 4.0 * deltaY * deltaY;
            b = 1.0 * ((-8.0) * p2.Y * deltaX * deltaX - 4.0 * A_ * deltaY + 8.0 * p2.X * deltaX * deltaY);
            c = 1.0 *
                ((p2.Y * p2.Y * 4.0 * deltaX * deltaX) + 1.0 * (A_ * A_) - (A_ * 4.0 * p2.X * deltaX) +
                 (4.0 * p2.X * p2.X * deltaX * deltaX) - (4.0 * l2 * l2 * deltaX * deltaX));

            D = 1.0 * b * b - 4.0 * a * c;
            if (D < 0)
            {
                D = 0;
            }

            y1 = ((-1.0) * b + Math.Sqrt(D)) / (2.0 * a);
            y2 = ((-1.0) * b - Math.Sqrt(D)) / (2.0 * a);
            if ((p2.X - p1.X) == 0)
            {
                x1 = 1.0 * p1.X - Math.Sqrt(1.0 * l1 * l1 - 1.0 * (p1.Y - y1) * (p1.Y - y1));
                x2 = 1.0 * p1.X + Math.Sqrt(1.0 * l2 * l2 - 1.0 * (p2.Y - y2) * (p2.Y - y2));
            }
            else
            {
                x1 = ((1.0 * l1 * l1 - 1.0 * p1.X * p1.X - 1.0 * l2 * l2 - 1.0 * p1.Y * p1.Y + 1.0 * p2.X * p2.X +
                       1.0 * p2.Y * p2.Y) - 2.0 * y1 * (p2.Y - p1.Y)) / (2.0 * (p2.X - p1.X));
                x2 = ((1.0 * l1 * l1 - 1.0 * p1.X * p1.X - 1.0 * l2 * l2 - 1.0 * p1.Y * p1.Y + 1.0 * p2.X * p2.X +
                       1.0 * p2.Y * p2.Y) - 2.0 * y2 * (p2.Y - p1.Y)) / (2.0 * (p2.X - p1.X));
            }

            p.X = (int)Math.Round(x1);
            p.Y = (int)Math.Round(y1);
            if (gp.IsVisible(p))
            {
                p_l = p;
            }

            p.X = (int)Math.Round(x2);
            p.Y = (int)Math.Round(y2);
            if (gp.IsVisible(p) && (p_l.X != -1000))
            {
                p_r = p;
            }
            else if (gp.IsVisible(p))
            {
                p_l = p;
            }
        }

        /// <summary>
        /// Нахождение координит нового узла, находящегося внутри некоторой области (для 3-го критерия)
        /// </summary>
        /// <param name="p1">
        /// координаты первой точки, от которой строится новый узел
        /// </param>
        /// <param name="p2">
        /// координаты второй точки, от которой строится новый узел
        /// </param>
        /// <param name="l1">
        /// расстояние от первой точки до нового узла
        /// </param>
        /// <param name="l2">
        /// расстояние от второй точки до нового узла
        /// </param>
        /// <param name="p3">
        /// координаты точки, которая удаляется при построении нового узла
        /// </param>
        /// <param name="gp">
        /// область, ограничивающая возможные варианты построения нового узла
        /// </param>
        /// <param name="multiplier">
        /// The multiplier.
        /// </param>
        /// <returns>
        /// координаты нового узла
        /// </returns>
        public Point FindPointFor34(Point p1, Point p2, double l1, double l2, Point p3, GraphicsPath gp, int multiplier)
        {
            var p = new Point();

            double a, b, c, D, x1, x2, y1, y2, A_, h, Square;
            double deltaX = 1.0 * (p2.X - p1.X);
            double deltaY = 1.0 * (p2.Y - p1.Y);
            A_ = 1.0 *
                 (1.0 * (l1 * l1) - 1.0 * (p1.X * p1.X) - 1.0 * (l2 * l2) - 1.0 * (p1.Y * p1.Y) + 1.0 * (p2.X * p2.X) +
                  1.0 * (p2.Y * p2.Y));
            a = 4.0 * deltaX * deltaX + 4.0 * deltaY * deltaY;
            b = 1.0 * ((-8.0) * p2.Y * deltaX * deltaX - 4.0 * A_ * deltaY + 8.0 * p2.X * deltaX * deltaY);
            c = 1.0 *
                ((p2.Y * p2.Y * 4.0 * deltaX * deltaX) + 1.0 * (A_ * A_) - (A_ * 4.0 * p2.X * deltaX) +
                 (4.0 * p2.X * p2.X * deltaX * deltaX) - (4.0 * l2 * l2 * deltaX * deltaX));

            D = 1.0 * b * b - 4.0 * a * c;
            if (D < 0)
            {
                D = 0;
            }

            y1 = ((-1.0) * b + Math.Sqrt(D)) / (2.0 * a);
            y2 = ((-1.0) * b - Math.Sqrt(D)) / (2.0 * a);
            if ((p2.X - p1.X) == 0)
            {
                x1 = 1.0 * p1.X - Math.Sqrt(1.0 * l1 * l1 - 1.0 * (p1.Y - y1) * (p1.Y - y1));
                x2 = 1.0 * p1.X + Math.Sqrt(1.0 * l2 * l2 - 1.0 * (p2.Y - y2) * (p2.Y - y2));
            }
            else
            {
                x1 = ((1.0 * l1 * l1 - 1.0 * p1.X * p1.X - 1.0 * l2 * l2 - 1.0 * p1.Y * p1.Y + 1.0 * p2.X * p2.X +
                       1.0 * p2.Y * p2.Y) - 2.0 * y1 * (p2.Y - p1.Y)) / (2.0 * (p2.X - p1.X));
                x2 = ((1.0 * l1 * l1 - 1.0 * p1.X * p1.X - 1.0 * l2 * l2 - 1.0 * p1.Y * p1.Y + 1.0 * p2.X * p2.X +
                       1.0 * p2.Y * p2.Y) - 2.0 * y2 * (p2.Y - p1.Y)) / (2.0 * (p2.X - p1.X));
            }

            Square = this.GeronLaw(p1, p2, p3, multiplier); // Площадь треугольника
            h = 2.0 * Square / (this.FindDist(p1, p2) / multiplier); // Высота треугольника

            p.X = (int)Math.Round(x1);
            p.Y = (int)Math.Round(y1);
            if (gp.IsVisible(p) && ((this.FindDist(p, p3) / multiplier) >= h))
            {
                return p;
            }

            p.X = (int)Math.Round(x2);
            p.Y = (int)Math.Round(y2);
            if (gp.IsVisible(p) && ((this.FindDist(p, p3) / multiplier) >= h))
            {
                return p;
            }

            return new Point(-1000, -1000);
        }

        /// <summary>
        /// Нахождение координат узла, лежащего на окружности
        /// </summary>
        /// <param name="p1">
        /// координаты центра окружности
        /// </param>
        /// <param name="p2">
        /// первая точка дуги
        /// </param>
        /// <param name="l1">
        /// расстояние от центра окружности до новой точки дуги
        /// </param>
        /// <param name="l2">
        /// расстояние от первой точки дуги до новой точки
        /// </param>
        /// <param name="pC">
        /// вторая точка дуги
        /// </param>
        /// <returns>
        /// координаты нового узла на окружности
        /// </returns>
        public Point FindPointOnCircle(Point p1, Point p2, double l1, double l2, Point pC)
        {
            var p = new Point();

            double a, b, c, D, x1, x2, y1, y2, A_;
            double deltaX = 1.0 * (p2.X - p1.X);
            double deltaY = 1.0 * (p2.Y - p1.Y);
            A_ = 1.0 *
                 (1.0 * (l1 * l1) - 1.0 * (p1.X * p1.X) - 1.0 * (l2 * l2) - 1.0 * (p1.Y * p1.Y) + 1.0 * (p2.X * p2.X) +
                  1.0 * (p2.Y * p2.Y));
            a = 4.0 * deltaX * deltaX + 4.0 * deltaY * deltaY;
            b = 1.0 * ((-8.0) * p2.Y * deltaX * deltaX - 4.0 * A_ * deltaY + 8.0 * p2.X * deltaX * deltaY);
            c = 1.0 *
                ((p2.Y * p2.Y * 4.0 * deltaX * deltaX) + 1.0 * (A_ * A_) - (A_ * 4.0 * p2.X * deltaX) +
                 (4.0 * p2.X * p2.X * deltaX * deltaX) - (4.0 * l2 * l2 * deltaX * deltaX));

            D = 1.0 * b * b - 4.0 * a * c;
            if (D < 0)
            {
                D = 0;
            }

            y1 = ((-1.0) * b + Math.Sqrt(D)) / (2.0 * a);
            y2 = ((-1.0) * b - Math.Sqrt(D)) / (2.0 * a);
            if ((p2.X - p1.X) == 0)
            {
                x1 = 1.0 * p1.X - Math.Sqrt(1.0 * l1 * l1 - 1.0 * (p1.Y - y1) * (p1.Y - y1));
                x2 = 1.0 * p1.X + Math.Sqrt(1.0 * l2 * l2 - 1.0 * (p2.Y - y2) * (p2.Y - y2));
            }
            else
            {
                x1 = ((1.0 * l1 * l1 - 1.0 * p1.X * p1.X - 1.0 * l2 * l2 - 1.0 * p1.Y * p1.Y + 1.0 * p2.X * p2.X +
                       1.0 * p2.Y * p2.Y) - 2.0 * y1 * (p2.Y - p1.Y)) / (2.0 * (p2.X - p1.X));
                x2 = ((1.0 * l1 * l1 - 1.0 * p1.X * p1.X - 1.0 * l2 * l2 - 1.0 * p1.Y * p1.Y + 1.0 * p2.X * p2.X +
                       1.0 * p2.Y * p2.Y) - 2.0 * y2 * (p2.Y - p1.Y)) / (2.0 * (p2.X - p1.X));
            }

            double MaxX, MinX, MaxY, MinY; // Точки, ограничивающие область дуги
            if (p2.X > pC.X)
            {
                MaxX = p2.X;
                MinX = pC.X;
            }
            else
            {
                MaxX = pC.X;
                MinX = p2.X;
            }

            if (p2.Y > pC.Y)
            {
                MaxY = p2.Y;
                MinY = pC.Y;
            }
            else
            {
                MaxY = pC.Y;
                MinY = p2.Y;
            }

            p.X = (int)Math.Round(x1);
            p.Y = (int)Math.Round(y1);
            if ((p.X >= MinX) && (p.X <= MaxX) && (p.Y >= MinY) && (p.Y <= MaxY))
            {
                return p;
            }

            p.X = (int)Math.Round(x2);
            p.Y = (int)Math.Round(y2);
            if ((p.X >= MinX) && (p.X <= MaxX) && (p.Y >= MinY) && (p.Y <= MaxY))
            {
                return p;
            }

            return new Point(-1000, -1000);
        }

        /// <summary>
        /// Проверка положения трёх точек на окружности заданного радиуса
        /// </summary>
        /// <param name="p1">
        /// первая точка
        /// </param>
        /// <param name="p2">
        /// вторая точка
        /// </param>
        /// <param name="p3">
        /// третья точка
        /// </param>
        /// <param name="R">
        /// радиус окружности
        /// </param>
        /// <param name="multiplier">
        /// The multiplier.
        /// </param>
        /// <returns>
        /// координаты центра окружности, иначе точка (-1000;-1000)
        /// </returns>
        public Point IsCircle(Point p1, Point p2, Point p3, double R, int multiplier)
        {
            var pCenter = new Point(-1000, -1000); // Координаты центра окружности
            double a, b, c, D, A_, x1, x2, y1, y2, delta1, delta2;
            A_ = 1.0 * (p2.X * p2.X + p2.Y * p2.Y - p1.X * p1.X - p1.Y * p1.Y);
            a = 4.0 * (p2.X - p1.X) * (p2.X - p1.X) + 4.0 * (p2.Y - p1.Y) * (p2.Y - p1.Y);
            b = 8.0 * p2.X * (p2.X - p1.X) * (p2.Y - p1.Y) - 8.0 * p2.Y * (p2.X - p1.X) * (p2.X - p1.X) -
                4.0 * A_ * (p2.Y - p1.Y);
            c = 4.0 * (p2.X - p1.X) * (p2.X - p1.X) * (p2.X * p2.X + p2.Y * p2.Y - R * R) -
                4.0 * p2.X * (p2.X - p1.X) * A_ + A_ * A_;
            D = b * b - 4.0 * a * c;
            if (D < 0)
            {
                D = 0;
            }

            y1 = ((-1.0) * b + Math.Sqrt(D)) / (2.0 * a);
            y2 = ((-1.0) * b - Math.Sqrt(D)) / (2.0 * a);
            if (p2.X == p1.X)
            {
                x1 = 1.0 * p1.X - R;
                x2 = 1.0 * p1.X + R;
            }
            else
            {
                x1 = 1.0 * (p2.X * p2.X + p2.Y * p2.Y - p1.X * p1.X - p1.Y * p1.Y - 2.0 * y1 * (p2.Y - p1.Y)) /
                     (2.0 * (p2.X - p1.X));
                x2 = 1.0 * (p2.X * p2.X + p2.Y * p2.Y - p1.X * p1.X - p1.Y * p1.Y - 2.0 * y2 * (p2.Y - p1.Y)) /
                     (2.0 * (p2.X - p1.X));
            }

            delta1 = 1.0 * (p3.X - x1) * (p3.X - x1) + 1.0 * (p3.Y - y1) * (p3.Y - y1) - R * R;
            delta2 = 1.0 * (p3.X - x2) * (p3.X - x2) + 1.0 * (p3.Y - y2) * (p3.Y - y2) - R * R;
            if (Math.Abs(delta1) < multiplier * 100)
            {
                pCenter = new Point((int)Math.Round(x1), (int)Math.Round(y1));
            }

            if (Math.Abs(delta2) < multiplier * 100)
            {
                pCenter = new Point((int)Math.Round(x2), (int)Math.Round(y2));
            }

            return pCenter;
        }

        /// <summary>
        /// Нахождение площади треугольник по формуле Герона
        /// </summary>
        /// <param name="p1">
        /// Координаты 1-й точки треугольника
        /// </param>
        /// <param name="p2">
        /// Координаты 2-й точки треугольника
        /// </param>
        /// <param name="p3">
        /// Координаты 3-й точки треугольника
        /// </param>
        /// <param name="multiplier">
        /// The multiplier.
        /// </param>
        /// <returns>
        /// Площадь треугольника
        /// </returns>
        public double GeronLaw(Point p1, Point p2, Point p3, int multiplier)
        {
            double Square = -1;
            double a, b, c, p;
            a = this.FindDist(p1, p2) / multiplier;
            b = this.FindDist(p2, p3) / multiplier;
            c = this.FindDist(p3, p1) / multiplier;
            p = (a + b + c) / 2.0;
            Square = Math.Sqrt(p * (p - a) * (p - b) * (p - c));
            return Square;
        }

        /// <summary>
        /// Нахождение уравнения прямой в виде y=kx+b, заданной двумя точками
        /// </summary>
        /// <param name="p1">
        /// Точка 1 прямой
        /// </param>
        /// <param name="p2">
        /// Точка 2 прямой
        /// </param>
        /// <param name="k">
        /// Коэффициент k
        /// </param>
        /// <param name="b">
        /// Коэффициент b
        /// </param>
        public void FindLineEquation(Point p1, Point p2, ref double k, ref double b)
        {
            if (p2.X == p1.X)
            {
                k = 0;
            }
            else
            {
                k = 1.0 * (p2.Y - p1.Y) / (p2.X - p1.X);
            }

            b = 1.0 * p1.Y - k * p1.X;
        }

        /// <summary>
        /// Нахождение узла, отстоящего от начальной точки startP на расстояние R и лежащего на прямой, заданной коэффициентами K_ и B_
        /// </summary>
        /// <param name="K_">
        /// Коэффициент k уравнения прямой
        /// </param>
        /// <param name="B_">
        /// Коэффициент b уравнения прямой
        /// </param>
        /// <param name="startP">
        /// Начальная точка
        /// </param>
        /// <param name="R">
        /// Расстояние от начальной точки
        /// </param>
        /// <param name="gp">
        /// Область, ограничивающая возможные варианты построения нового узла
        /// </param>
        /// <returns>
        /// Координаты узла
        /// </returns>
        public Point FindNewCoord(double K_, double B_, Point startP, double R, GraphicsPath gp)
        {
            var p = new Point();
            double a, b, c, D, x1, y1, x2, y2;
            a = 1.0 + K_ * K_;
            b = 2.0 * B_ * K_ - 2.0 * startP.X - 2.0 * K_ * startP.Y;
            c = 1.0 * startP.X * startP.X + B_ * B_ - 2.0 * startP.Y * B_ + 1.0 * startP.Y * startP.Y - R * R;
            D = 1.0 * b * b - 4.0 * a * c;
            if (D < 0)
            {
                D = 0;
            }

            x1 = ((-1.0) * b + Math.Sqrt(D)) / (2.0 * a);
            x2 = ((-1.0) * b - Math.Sqrt(D)) / (2.0 * a);
            y1 = K_ * x1 + B_;
            y2 = K_ * x2 + B_;

            p.X = (int)Math.Round(x1);
            p.Y = (int)Math.Round(y1);
            if (gp.IsVisible(p))
            {
                return p;
            }

            p.X = (int)Math.Round(x2);
            p.Y = (int)Math.Round(y2);
            if (gp.IsVisible(p))
            {
                return p;
            }

            return new Point(-1000, -1000);
        }

        /// <summary>
        /// Нахождение значения функции плотности в некоторой точке
        /// </summary>
        /// <param name="p">
        /// Координаты точки, в которой осуществляется поиск функции плотности
        /// </param>
        /// <param name="points">
        /// Список координат точек текущей зоны, для которых задана функция плотности
        /// </param>
        /// <param name="values">
        /// Значения функций плотности в точках текущей зоны, для которых задана функция плотности
        /// </param>
        /// <param name="avg">
        /// Значение функции плотности по умолчанию
        /// </param>
        /// <param name="multiplier">
        /// множитель
        /// </param>
        /// <returns>
        /// Значение функции плотности в искомой точке
        /// </returns>
        public double FindDensityFuncInPoint(
            Point p, List<Point> points, List<double> values, double avg, int multiplier)
        {
            double density = 0;
            var NearValues = new List<double>(1);
            var Koefs = new List<double>(1);
            for (int i = 0; i < points.Count; i++)
            {
                if (this.FindDist(p, points[i]) / multiplier <= 10)
                {
                    NearValues.Add(values[i]);
                    Koefs.Add(1.0 - this.FindDist(p, points[i]) / (10.0 * multiplier));
                }
            }

            if (NearValues.Count == 0)
            {
                return avg * multiplier;
            }

            for (int i = 0; i < NearValues.Count; i++)
            {
                density = density + NearValues[i] * Koefs[i];
            }

            density += avg * 0.75;
            density = density / (NearValues.Count + 1);
            return density * multiplier;
        }
    }
}